本文为原创文章,欢迎转载!转载时请注明出处:http://blog.csdn.net/windskier
这篇文章开始从framework的角度来研究一下android四大控件最后一个控件BroadcastReceiver 的机制与原理,BroadcastReceiver 字面意思就是广播接收器,它能接收来自于系统的以及其他appliaction的广播消息,是android中非常重要的一个component。
1. BroadcastReceiver注册
BroadcastReceiver的注册有两种方式,一种是通过Context.registerReceiver()方法来进行动态注册,或者通过在AndroidManifest.xml中进行静态注册。AMS对两种不同注册方式的Receiver有不同的管理方式。静态注册就不用说了,静态注册的receiver的管理是有PMS负责的,而AMS则需要对动态注册的receiver注册和管理。下面就研究一下AMS对receiver的动态管理过程。
1.1 ReceiverDispatcher
同Service一样,LoadedApk为receiver提供了一个ReceiverDispatcher类型,类似于Service管理时的ServiceDispatcher类型,对于每个要注册的receiver,LoadedApk会为其创建一个ReceiverDispatcher。从其名称来看,ReceiverDispatcher就是向receiver dispatch广播信息,下面简单介绍一下这个类型存在的价值,广播信息是经由AMS进行分发管理的,因此需要为AMS向receive分发广播消息设计一个接口,通过这个接口可以实现receiver与AMS的IPC通信,BroadcastReceiver 本身并不是一个IBinder接口,因此需要单独设计一个,这个接口就是InnerReceiver,InnerReceiver一方面与AMS进行IPC通信,另一方面还需要与receiver进行交互,为了区分IPC的接口方法和与receiver的交互接口,这里需要定义了另外一个类型ReceiverDispatcher,这就是ReceiverDispatcher产生的原因。
@ContextImpl.java
private Intent registerReceiverInternal(BroadcastReceiver receiver,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context) {
IIntentReceiver rd = null;
if (receiver != null) {
if (mPackageInfo != null && context != null) {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
} else {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = new LoadedApk.ReceiverDispatcher(
receiver, context, scheduler, null, true).getIIntentReceiver();
}
}
try {
return ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission);
} catch (RemoteException e) {
return null;
}
}
1.2 InnerReceiver
上面一节已经介绍了InnerReceiver存在的意义,它其实是一个IInterface,用于AMS和Receiver之间的IPC通信,InnerReceiver实现了接口IIntentReceiver。
@IIntentReceiver.aidl
oneway interface IIntentReceiver {
void performReceive(in Intent intent, int resultCode,
String data, in Bundle extras, boolean ordered, boolean sticky);
}